/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package expression;

import core.Node;
import core.UnsatException;
import domain.Domain;

/**
 *
 * @author ddoose
 */
public class Or extends IntExpr {
    
    public Or(Node n) {
        super(n);
        current = Domain.BOOLEAN;
        target = Domain.BOOLEAN;
    }
    
    public Or(Node c, IntExpr[] p) {
        super(c, p);
        current = Domain.BOOLEAN;
        target = Domain.BOOLEAN;
    }
    
    public boolean same(IntExpr i) {
        return (i instanceof Or) && sameParameters(i);
    }

    public void eval() throws UnsatException {
        boolean b = true;
        
        for (int i = 0; i < getParameters().size(); i++) {
            int index = getParameters().get(i);
            Domain p = node.getIntExpr(index).current;

            // TRUE
            if (p.isTrue()) {
                reduceCurrent(Domain.TRUE);
                return;
            }
            // PARTIAL FALSE
            else if (b && !p.isFalse()) {
                b = false;
            }
        }
        // FALSE
        if (b) {
            reduceCurrent(Domain.FALSE);
        }
    }

    public void propagate() throws UnsatException {
        if (target.isFalse()) {
            for (int i: getParameters()) {
                IntExpr p = node.getIntExpr(i);
                p.reduceTarget(Domain.FALSE);
            }
        }
    }
    
    public boolean reduce() {
        // FALSE
        if (current.isFalse()) {
            Value v = node.createValue(0);
            node.replaceIntExpr(id, v.getId());
            return true;
        }
        // TRUE
        if (current.isTrue()) {
            Value v = node.createValue(1);
            node.replaceIntExpr(id, v.getId());
            return true;
        }
        // si un and on applati
        for (int i = 0; i < getParameters().size(); i++) {
            int index = getParameters().get(i);
            IntExpr p = node.getIntExpr(index);
            if (p instanceof Or) {
                int length = node.getNexts(id).size() + node.getNexts(index).size();
                IntExpr[] temp = new IntExpr[length];
                int j = 0;
                for (int k: node.getNexts(id)) {
                    if (k != index) {
                        temp[j++] = node.getIntExpr(k);
                    }
                }
                for (int k: node.getNexts(index)) {
                    temp[j++] = node.getIntExpr(k);
                }
                Or or = node.createOr(temp);
                node.replaceIntExpr(id, or.getId());
                return true;
            }
        }
        boolean b = false;
        // remove True
        for (int i = 0; i < getParameters().size(); i++) {
            int index = getParameters().get(i);
            IntExpr p = node.getIntExpr(index);

            if (p.current.isTrue()) {
                node.removeDependency(id, p.getId());
                i--;
                b = true;
            }
        }
        // un seul paramètre
        if (getParameters().size() == 1) {
            node.removeIntExpr(this);
            return true;
        }
        return b;
    }
    
    public Or clone(Node n) {
        Or or = new Or(n);
        or.clone(this);
        return or;
    }
    
    public String toString() {
        String s = "(or";
        for (int i: getParameters()) {
            IntExpr p = node.getIntExpr(i);
            s += " " + p;
        }
        s += ")";
        
        return s;
    }
    
    public String pretty() {
        return id + "\t" + current + "\t" + target + "\t" + toString();
    }
}
